"""
Aspose.Slides PPT builder for converting structured content to PowerPoint presentations.

This builder provides native PowerPoint animation support using Aspose.Slides,
replacing the python-pptx implementation for enhanced animation capabilities.
"""

import logging
from pathlib import Path
from typing import List, Optional, Union, Any
import tempfile
import shutil

try:
    import aspose.slides as slides
    from aspose.slides import Presentation, SlideLayoutType, TextAlignment
    from aspose.slides.animation import EffectType, EffectSubtype, EffectTriggerType
    ASPOSE_AVAILABLE = True
except ImportError:
    ASPOSE_AVAILABLE = False
    slides = None
    Presentation = None

from ..parser.content_types import (
    AnimatedContent,
    BulletListContent,
    CodeBlockContent,
    ContentNode,
    ContentType,
    DocumentStructure,
    ImageContent,
    VideoContent,
    Section,
    TextContent,
)
from ..styling.theme_manager import ThemeManager
from ..media.image_processor import ImageProcessor
from ..media.video_processor import VideoProcessor
from ..animation.engines.aspose_engine import AsposeAnimationEngine, create_aspose_engine
from ..utils.exceptions import MD2PPTError


class AsposePPTBuilder:
    """使用Aspose.Slides构建PowerPoint演示文稿"""
    
    def __init__(self, theme_name: str = "default", enable_animations: bool = True):
        if not ASPOSE_AVAILABLE:
            raise MD2PPTError(
                "Aspose.Slides not available. Install with: pip install aspose-slides-python"
            )
        
        self.theme_name = theme_name
        self.enable_animations = enable_animations
        self.logger = logging.getLogger(__name__)
        
        # 初始化组件
        self.theme_manager = ThemeManager(theme_name)
        self.image_processor = ImageProcessor(self.theme_manager)
        self.video_processor = VideoProcessor(self.theme_manager)
        
        # 初始化动画引擎
        self.animation_engine = None
        if enable_animations:
            self.animation_engine = create_aspose_engine()
            if not self.animation_engine:
                self.logger.warning("Animation engine not available, animations disabled")
                self.enable_animations = False
        
        self.presentation = None
        self.current_slide = None
    
    def build_from_structure(self, doc_structure: DocumentStructure) -> Any:
        """从文档结构构建PowerPoint演示文稿"""
        try:
            # 创建新演示文稿
            self.presentation = Presentation()
            
            # 移除默认幻灯片
            if self.presentation.slides.length > 0:
                self.presentation.slides.remove_at(0)
            
            # 应用主题
            self._apply_theme()
            
            # 处理章节
            slide_count = 0
            for section in doc_structure.sections:
                if section.is_title_slide:
                    self._create_title_slide(section)
                    slide_count += 1
                elif section.is_content_slide or section.level >= 2:
                    self._create_content_slide(section)
                    slide_count += 1
            
            # 如果没有创建任何幻灯片，创建默认标题幻灯片
            if slide_count == 0:
                self._create_default_title_slide(doc_structure.title)
            
            self.logger.info(f"Successfully created presentation with {slide_count} slides")
            return self.presentation
            
        except Exception as e:
            self.logger.error(f"Failed to build presentation: {e}")
            raise MD2PPTError(f"Presentation building failed: {e}")
    
    def save(self, output_path: str) -> None:
        """保存演示文稿到文件"""
        if not self.presentation:
            raise MD2PPTError("No presentation to save. Call build_from_structure first.")
        
        try:
            output_path = Path(output_path)
            output_path.parent.mkdir(parents=True, exist_ok=True)
            
            # 保存为PPTX格式
            self.presentation.save(str(output_path), slides.export.SaveFormat.PPTX)
            self.logger.info(f"Presentation saved to: {output_path}")
            
        except Exception as e:
            self.logger.error(f"Failed to save presentation: {e}")
            raise MD2PPTError(f"Failed to save presentation: {e}")
    
    def _apply_theme(self):
        """应用主题样式"""
        try:
            # 设置幻灯片大小 (16:9)
            self.presentation.slide_size.set_size(slides.SlideSizeType.ON_SCREEN16X9)
            
            # 应用主题色彩 (基于theme_manager的设置)
            # 这里可以根据需要自定义主题
            pass
            
        except Exception as e:
            self.logger.warning(f"Failed to apply theme: {e}")
    
    def _create_title_slide(self, section: Section) -> Any:
        """创建标题幻灯片"""
        try:
            # 添加新幻灯片 (标题布局)
            layout = self.presentation.masters[0].layout_slides[0]  # Title layout
            slide = self.presentation.slides.add_slide(layout)
            self.current_slide = slide
            
            # 添加标题
            title_placeholder = slide.shapes.title
            if title_placeholder:
                title_placeholder.text_frame.text = section.heading
                self._style_title_text(title_placeholder)
            
            # 添加副标题内容
            if section.content and hasattr(slide.shapes, 'placeholders') and len(slide.shapes.placeholders) > 1:
                subtitle_text = self._extract_text_from_content(section.content)
                if subtitle_text:
                    subtitle_placeholder = slide.shapes.placeholders[1]
                    subtitle_placeholder.text_frame.text = subtitle_text
                    self._style_subtitle_text(subtitle_placeholder)
            
            return slide
            
        except Exception as e:
            self.logger.error(f"Failed to create title slide: {e}")
            return None
    
    def _create_content_slide(self, section: Section) -> Any:
        """创建内容幻灯片"""
        try:
            # 添加新幻灯片 (内容布局)
            layout = self.presentation.masters[0].layout_slides[1]  # Content layout
            slide = self.presentation.slides.add_slide(layout)
            self.current_slide = slide
            
            # 添加幻灯片标题
            if slide.shapes.title:
                slide.shapes.title.text_frame.text = section.heading
                self._style_slide_title(slide.shapes.title)
            
            # 添加内容
            content_y = 150  # 起始Y位置 (点)
            for content_node in section.content:
                content_y = self._add_content_to_slide(slide, content_node, content_y)
            
            return slide
            
        except Exception as e:
            self.logger.error(f"Failed to create content slide: {e}")
            return None
    
    def _add_content_to_slide(self, slide, content_node: ContentNode, current_y: float) -> float:
        """向幻灯片添加内容节点"""
        try:
            if content_node.type == ContentType.TEXT:
                return self._add_text_content(slide, content_node.data, current_y)
            
            elif content_node.type == ContentType.BULLET_LIST:
                return self._add_bullet_list(slide, content_node.data, current_y)
            
            elif content_node.type == ContentType.IMAGE:
                return self._add_image_content(slide, content_node.data, current_y)
            
            elif content_node.type == ContentType.VIDEO:
                return self._add_video_content(slide, content_node.data, current_y)
            
            elif content_node.type == ContentType.CODE_BLOCK:
                return self._add_code_block(slide, content_node.data, current_y)
            
            elif content_node.type == ContentType.ANIMATED_CONTENT:
                return self._add_animated_content(slide, content_node.data, current_y)
            
            return current_y
            
        except Exception as e:
            self.logger.error(f"Failed to add content: {e}")
            return current_y + 50  # 跳过错误内容
    
    def _add_text_content(self, slide, text_content: TextContent, current_y: float) -> float:
        """添加文本内容"""
        try:
            # 计算文本框尺寸
            text_height = max(50, len(text_content.text.split('\n')) * 25)
            
            # 创建文本框
            text_box = slide.shapes.add_auto_shape(
                slides.ShapeType.RECTANGLE,
                50,      # X位置
                current_y,  # Y位置
                640,     # 宽度
                text_height  # 高度
            )
            
            # 设置文本
            text_box.text_frame.text = text_content.text
            
            # 设置样式
            self._style_body_text(text_box)
            
            return current_y + text_height + 20
            
        except Exception as e:
            self.logger.error(f"Failed to add text content: {e}")
            return current_y + 50
    
    def _add_bullet_list(self, slide, bullet_content: BulletListContent, current_y: float) -> float:
        """添加项目符号列表"""
        try:
            # 计算列表高度
            list_height = len(bullet_content.items) * 30 + 20
            
            # 创建文本框
            text_box = slide.shapes.add_auto_shape(
                slides.ShapeType.RECTANGLE,
                50,
                current_y,
                640,
                list_height
            )
            
            # 构建项目符号文本
            bullet_text = '\n'.join(f"• {item}" for item in bullet_content.items)
            text_box.text_frame.text = bullet_text
            
            # 设置样式
            self._style_bullet_list(text_box)
            
            return current_y + list_height + 20
            
        except Exception as e:
            self.logger.error(f"Failed to add bullet list: {e}")
            return current_y + 50
    
    def _add_image_content(self, slide, image_content: ImageContent, current_y: float) -> float:
        """添加图片内容"""
        try:
            image_path = Path(image_content.path)
            if not image_path.exists():
                # 图片不存在时添加占位符
                return self._add_placeholder_text(slide, f"[图片未找到: {image_content.path}]", current_y)
            
            # 添加图片
            with open(image_path, 'rb') as img_file:
                image = slide.shapes.add_picture_frame(
                    slides.ShapeType.RECTANGLE,
                    50,      # X位置
                    current_y,  # Y位置
                    400,     # 宽度
                    300,     # 高度 (将根据实际图片调整)
                    img_file.read()
                )
            
            return current_y + 320  # 图片高度 + 边距
            
        except Exception as e:
            self.logger.error(f"Failed to add image: {e}")
            return self._add_placeholder_text(slide, f"[图片加载失败: {image_content.path}]", current_y)
    
    def _add_video_content(self, slide, video_content: VideoContent, current_y: float) -> float:
        """添加视频内容"""
        try:
            video_path = Path(video_content.path)
            if not video_path.exists():
                return self._add_placeholder_text(slide, f"[视频未找到: {video_content.path}]", current_y)
            
            # 添加视频 (Aspose.Slides支持视频嵌入)
            with open(video_path, 'rb') as video_file:
                video = slide.shapes.add_video_frame(
                    50,      # X位置
                    current_y,  # Y位置
                    480,     # 宽度
                    360,     # 高度
                    video_file.read()
                )
            
            return current_y + 380  # 视频高度 + 边距
            
        except Exception as e:
            self.logger.error(f"Failed to add video: {e}")
            return self._add_placeholder_text(slide, f"[视频加载失败: {video_content.path}]", current_y)
    
    def _add_code_block(self, slide, code_content: CodeBlockContent, current_y: float) -> float:
        """添加代码块"""
        try:
            # 计算代码块高度
            code_lines = code_content.code.split('\n')
            code_height = len(code_lines) * 20 + 40
            
            # 创建代码框
            code_box = slide.shapes.add_auto_shape(
                slides.ShapeType.RECTANGLE,
                50,
                current_y,
                640,
                code_height
            )
            
            # 设置代码文本
            display_text = code_content.code
            if code_content.language:
                display_text = f"[{code_content.language}]\n{display_text}"
            
            code_box.text_frame.text = display_text
            
            # 设置代码样式
            self._style_code_block(code_box)
            
            return current_y + code_height + 20
            
        except Exception as e:
            self.logger.error(f"Failed to add code block: {e}")
            return current_y + 50
    
    def _add_animated_content(self, slide, animated_content: AnimatedContent, current_y: float) -> float:
        """添加带动画的内容"""
        try:
            # 首先添加普通内容
            new_y = self._add_content_to_slide(slide, animated_content.content, current_y)
            
            # 如果动画引擎可用，为最后添加的形状添加动画
            if self.enable_animations and self.animation_engine:
                # 获取最后添加的形状
                if slide.shapes.length > 0:
                    last_shape = slide.shapes[slide.shapes.length - 1]
                    
                    # 添加动画效果
                    success = self.animation_engine.add_animation_to_shape(
                        slide, last_shape, animated_content
                    )
                    
                    if success:
                        self.logger.info(
                            f"Applied {animated_content.animation_type} animation "
                            f"(duration: {animated_content.duration}s, delay: {animated_content.delay}s)"
                        )
                    else:
                        self.logger.warning(f"Failed to apply {animated_content.animation_type} animation")
            
            return new_y
            
        except Exception as e:
            self.logger.error(f"Failed to add animated content: {e}")
            return self._add_content_to_slide(slide, animated_content.content, current_y)
    
    def _add_placeholder_text(self, slide, text: str, current_y: float) -> float:
        """添加占位符文本"""
        text_box = slide.shapes.add_auto_shape(
            slides.ShapeType.RECTANGLE, 50, current_y, 640, 30
        )
        text_box.text_frame.text = text
        self._style_placeholder_text(text_box)
        return current_y + 50
    
    def _create_default_title_slide(self, title: str) -> Any:
        """创建默认标题幻灯片"""
        try:
            layout = self.presentation.masters[0].layout_slides[0]
            slide = self.presentation.slides.add_slide(layout)
            
            if slide.shapes.title:
                slide.shapes.title.text_frame.text = title
                self._style_title_text(slide.shapes.title)
            
            return slide
            
        except Exception as e:
            self.logger.error(f"Failed to create default title slide: {e}")
            return None
    
    def _extract_text_from_content(self, content_nodes: List[ContentNode]) -> str:
        """从内容节点提取文本"""
        text_parts = []
        for node in content_nodes[:3]:  # 限制副标题长度
            if node.type == ContentType.TEXT:
                text_parts.append(node.data.text)
            elif node.type == ContentType.BULLET_LIST:
                text_parts.extend(node.data.items[:2])  # 最多2个项目
        
        return '\n'.join(text_parts)[:150]  # 限制长度
    
    # 样式设置方法
    def _style_title_text(self, shape):
        """设置标题文本样式"""
        try:
            text_frame = shape.text_frame
            text_frame.text_frame_format.center_text = True
            
            # 设置字体
            paragraph = text_frame.paragraphs[0]
            paragraph.alignment = TextAlignment.CENTER
            portion = paragraph.portions[0]
            portion.portion_format.font_height = 44
            portion.portion_format.font_bold = True
            
        except Exception as e:
            self.logger.warning(f"Failed to style title text: {e}")
    
    def _style_subtitle_text(self, shape):
        """设置副标题文本样式"""
        try:
            paragraph = shape.text_frame.paragraphs[0]
            paragraph.alignment = TextAlignment.CENTER
            portion = paragraph.portions[0]
            portion.portion_format.font_height = 24
            
        except Exception as e:
            self.logger.warning(f"Failed to style subtitle text: {e}")
    
    def _style_slide_title(self, shape):
        """设置幻灯片标题样式"""
        try:
            paragraph = shape.text_frame.paragraphs[0]
            portion = paragraph.portions[0]
            portion.portion_format.font_height = 32
            portion.portion_format.font_bold = True
            
        except Exception as e:
            self.logger.warning(f"Failed to style slide title: {e}")
    
    def _style_body_text(self, shape):
        """设置正文文本样式"""
        try:
            paragraph = shape.text_frame.paragraphs[0]
            portion = paragraph.portions[0]
            portion.portion_format.font_height = 18
            
        except Exception as e:
            self.logger.warning(f"Failed to style body text: {e}")
    
    def _style_bullet_list(self, shape):
        """设置项目符号列表样式"""
        try:
            for paragraph in shape.text_frame.paragraphs:
                portion = paragraph.portions[0]
                portion.portion_format.font_height = 18
                
        except Exception as e:
            self.logger.warning(f"Failed to style bullet list: {e}")
    
    def _style_code_block(self, shape):
        """设置代码块样式"""
        try:
            # 设置等宽字体和样式
            for paragraph in shape.text_frame.paragraphs:
                portion = paragraph.portions[0]
                portion.portion_format.latin_font = slides.FontData("Consolas")
                portion.portion_format.font_height = 14
                
            # 设置背景色
            shape.fill_format.fill_type = slides.FillType.SOLID
            shape.fill_format.solid_fill_color.color = slides.drawing.Color.light_gray
            
        except Exception as e:
            self.logger.warning(f"Failed to style code block: {e}")
    
    def _style_placeholder_text(self, shape):
        """设置占位符文本样式"""
        try:
            paragraph = shape.text_frame.paragraphs[0]
            portion = paragraph.portions[0]
            portion.portion_format.font_height = 16
            portion.portion_format.font_italic = True
            
        except Exception as e:
            self.logger.warning(f"Failed to style placeholder text: {e}")
    
    @classmethod
    def is_available(cls) -> bool:
        """检查Aspose.Slides是否可用"""
        return ASPOSE_AVAILABLE
    
    def get_animation_info(self) -> dict:
        """获取动画引擎信息"""
        if not self.animation_engine:
            return {"available": False, "reason": "Animation engine not initialized"}
        
        return {
            "available": True,
            "engine": "Aspose.Slides",
            "supported_animations": self.animation_engine.get_supported_animations()
        }